"use client";

import type * as React from "react";

import { type PlateEditor, type PlateElementProps } from "platejs/react";

import { AIChatPlugin } from "@platejs/ai/react";
import {
  CalendarIcon,
  ChevronRightIcon,
  Code2,
  Columns3Icon,
  Heading1Icon,
  Heading2Icon,
  Heading3Icon,
  LightbulbIcon,
  ListIcon,
  ListOrdered,
  PilcrowIcon,
  Quote,
  RadicalIcon,
  SparklesIcon,
  Square,
  Table,
  TableOfContentsIcon,
} from "lucide-react";
import { type TComboboxInputElement, KEYS } from "platejs";
import { PlateElement } from "platejs/react";

import {
  insertBlock,
  insertInlineElement,
} from "@/components/plate/utils/transforms";

import {
  InlineCombobox,
  InlineComboboxContent,
  InlineComboboxEmpty,
  InlineComboboxGroup,
  InlineComboboxGroupLabel,
  InlineComboboxInput,
  InlineComboboxItem,
} from "./inline-combobox";

type Group = {
  group: string;
  items: Item[];
};

interface Item {
  icon: React.ReactNode;
  value: string;
  onSelect: (editor: PlateEditor, value: string) =&gt; void;
  className?: string;
  focusEditor?: boolean;
  keywords?: string[];
  label?: string;
}

const groups: Group[] = [
  {
    group: "AI",
    items: [
      {
        focusEditor: false,
        icon: &lt;SparklesIcon /&gt;,
        value: "AI",
        onSelect: (editor) =&gt; {
          editor.getApi(AIChatPlugin).aiChat.show();
        },
      },
    ],
  },
  {
    group: "Basic blocks",
    items: [
      {
        icon: &lt;PilcrowIcon /&gt;,
        keywords: ["paragraph"],
        label: "Text",
        value: KEYS.p,
      },
      {
        icon: &lt;Heading1Icon /&gt;,
        keywords: ["title", "h1"],
        label: "Heading 1",
        value: KEYS.h1,
      },
      {
        icon: &lt;Heading2Icon /&gt;,
        keywords: ["subtitle", "h2"],
        label: "Heading 2",
        value: KEYS.h2,
      },
      {
        icon: &lt;Heading3Icon /&gt;,
        keywords: ["subtitle", "h3"],
        label: "Heading 3",
        value: KEYS.h3,
      },
      {
        icon: &lt;ListIcon /&gt;,
        keywords: ["unordered", "ul", "-"],
        label: "Bulleted list",
        value: KEYS.ul,
      },
      {
        icon: &lt;ListOrdered /&gt;,
        keywords: ["ordered", "ol", "1"],
        label: "Numbered list",
        value: KEYS.ol,
      },
      {
        icon: &lt;Square /&gt;,
        keywords: ["checklist", "task", "checkbox", "[]"],
        label: "To-do list",
        value: KEYS.listTodo,
      },
      {
        icon: &lt;ChevronRightIcon /&gt;,
        keywords: ["collapsible", "expandable"],
        label: "Toggle",
        value: KEYS.toggle,
      },
      {
        icon: &lt;Code2 /&gt;,
        keywords: ["```"],
        label: "Code Block",
        value: KEYS.codeBlock,
      },
      {
        icon: <table />,
        label: "Table",
        value: KEYS.table,
      },
      {
        icon: &lt;Quote /&gt;,
        keywords: ["citation", "blockquote", "quote", "&gt;"],
        label: "Blockquote",
        value: KEYS.blockquote,
      },
      {
        description: "Insert a highlighted block.",
        icon: &lt;LightbulbIcon /&gt;,
        keywords: ["note"],
        label: "Callout",
        value: KEYS.callout,
      },
    ].map((item) =&gt; ({
      ...item,
      onSelect: (editor, value) =&gt; {
        insertBlock(editor, value);
      },
    })),
  },
  {
    group: "Advanced blocks",
    items: [
      {
        icon: &lt;TableOfContentsIcon /&gt;,
        keywords: ["toc"],
        label: "Table of contents",
        value: KEYS.toc,
      },
      {
        icon: &lt;Columns3Icon /&gt;,
        label: "3 columns",
        value: "action_three_columns",
      },
      {
        focusEditor: false,
        icon: &lt;RadicalIcon /&gt;,
        label: "Equation",
        value: KEYS.equation,
      },
    ].map((item) =&gt; ({
      ...item,
      onSelect: (editor, value) =&gt; {
        insertBlock(editor, value);
      },
    })),
  },
  {
    group: "Inline",
    items: [
      {
        focusEditor: true,
        icon: &lt;CalendarIcon /&gt;,
        keywords: ["time"],
        label: "Date",
        value: KEYS.date,
      },
      {
        focusEditor: false,
        icon: &lt;RadicalIcon /&gt;,
        label: "Inline Equation",
        value: KEYS.inlineEquation,
      },
    ].map((item) =&gt; ({
      ...item,
      onSelect: (editor, value) =&gt; {
        insertInlineElement(editor, value);
      },
    })),
  },
];

export function SlashInputElement(
  props: PlateElementProps&lt;TComboboxInputElement&gt;,
) {
  const { editor, element } = props;

  return (
    &lt;PlateElement {...props} as="span" data-slate-value={element.value}&gt;
      &lt;InlineCombobox element={element} trigger="/"&gt;
        &lt;InlineComboboxInput /&gt;

        &lt;InlineComboboxContent&gt;
          &lt;InlineComboboxEmpty&gt;No results&lt;/InlineComboboxEmpty&gt;

          {groups.map(({ group, items }) =&gt; (
            &lt;InlineComboboxGroup key={group}&gt;
              &lt;InlineComboboxGroupLabel&gt;{group}&lt;/InlineComboboxGroupLabel&gt;

              {items.map(
                ({ focusEditor, icon, keywords, label, value, onSelect }) =&gt; (
                  &lt;InlineComboboxItem
                    key={value}
                    value={value}
                    onClick={() =&gt; onSelect(editor, value)}
                    label={label}
                    focusEditor={focusEditor}
                    group={group}
                    keywords={keywords}
                  &gt;
                    <div>{icon}</div>
                    {label ?? value}
                  &lt;/InlineComboboxItem&gt;
                ),
              )}
            &lt;/InlineComboboxGroup&gt;
          ))}
        &lt;/InlineComboboxContent&gt;
      &lt;/InlineCombobox&gt;

      {props.children}
    &lt;/PlateElement&gt;
  );
}
